﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.IO.Ports;
using System.Text.RegularExpressions;
using System.Globalization;
using System.Threading;

namespace KoevServoAdjust
{
    public partial class MainForm : Form
    {
        SerialPort comport;
        List<byte> InputData = new List<byte>(2048);
        // This delegate enables asynchronous calls for setting
        // the text property on a TextBox control:
        delegate void SetTextCallback(string text);
        Dictionary<string, double[]> Limits = new Dictionary<string, double[]>(20);
        Dictionary<string, string> regexStrings = new Dictionary<string, string>(20);
        Dictionary<string, int> bitsAfterDot = new Dictionary<string, int>(20);
        public  EepromBank bank;
        public MainForm()
        {
            InitializeComponent();
            comboBank.SelectedIndex = 0;
            comboBoxSelectServo.SelectedIndex = 0;
            comboBoxCalcInterval.SelectedIndex = 0;
            comboBoxCOM.Items.AddRange(System.IO.Ports.SerialPort.GetPortNames());
            
            //string[] cmd = { "X", "V", "C", "c", "G", "S", "L", "A", "Z", "+", "U", "R", "W" };
            //comboBank.Items.AddRange(cmd);
            Limits.Add("textBoxPgain", new double[] { -127.99609375, 127.99609375 });
            Limits.Add("textBoxIgain", new double[] { -0.49998, 0.49998 });
            Limits.Add("textBoxDgain", new double[] { -127.99609375, 127.99609375 });
            Limits.Add("textBoxFF1", new double[] { -127.9375, 127.9375 });
            Limits.Add("textBoxMaxI", new double[] { 0, 127 });
            Limits.Add("textBoxMaxOutput", new double[] { 0, 260 });
            Limits.Add("textBoxBias", new double[] { -127, 127 });
            Limits.Add("textBoxDeadBand", new double[] { 0, 255 });
            Limits.Add("textBoxCmdMultiplier", new double[] { 1, 63 });
            Limits.Add("textBoxMaxError", new double[] { 1, 4095 });
            Limits.Add("textBoxAddress", new double[] { 0, 15 });

            regexStrings.Add("textBoxPgain",@"^[-+]*[0-9]+\.?[0-9]*$");
            regexStrings.Add("textBoxIgain", @"^[-+]*[0-9]+\.?[0-9]*$");
            regexStrings.Add("textBoxDgain",@"^[-+]*[0-9]+\.?[0-9]*$");
            regexStrings.Add("textBoxFF1",@"^[-+]*[0-9]+\.?[0-9]*$");
            regexStrings.Add("textBoxMaxI",@"^[+]*[0-9]+$");
            regexStrings.Add("textBoxMaxOutput",@"^[+]*[0-9]+$");
            regexStrings.Add("textBoxBias",@"^[-+]*[0-9]+$");
            regexStrings.Add("textBoxDeadBand",@"^[+]*[0-9]+$");
            regexStrings.Add("textBoxCmdMultiplier", @"^[+]*[0-9]+$");
            regexStrings.Add("textBoxMaxError",@"^[+]*[0-9]+$");
            regexStrings.Add("textBoxAddress", @"^[+]*[0-9]+$");

            bitsAfterDot.Add("textBoxPgain", 8);
            bitsAfterDot.Add("textBoxIgain", 16);
            bitsAfterDot.Add("textBoxDgain", 8);
            bitsAfterDot.Add("textBoxFF1", 4);
            bitsAfterDot.Add("textBoxMaxI", 0);
            bitsAfterDot.Add("textBoxMaxOutput", 0);
            bitsAfterDot.Add("textBoxBias", 0);
            bitsAfterDot.Add("textBoxDeadBand", 0);
            bitsAfterDot.Add("textBoxCmdMultiplier", 0);
            bitsAfterDot.Add("textBoxMaxError", 0);
            bitsAfterDot.Add("textBoxAddress", 0);

            bank = new EepromBank();            
        }

        private void comboBoxCOM_SelectedIndexChanged(object sender, EventArgs e)
        {
            if(comboBoxCOM.Items.Contains(comboBoxCOM.SelectedItem))
            {
                if (comport != null)
                {
                    if (comport.IsOpen)
                        comport.Close();
                    comport = null;
                }
                comport = new SerialPort((string)comboBoxCOM.SelectedItem, 9600, Parity.None, 8, StopBits.Two);
                this.comport.DataReceived += new SerialDataReceivedEventHandler(this.comport_DataReceived);
                comport.Open();
                
            }
        }
        private void comport_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            while (comport.BytesToRead > 0)
            {
                InputData.Add((byte)comport.ReadByte());
            }

            //if (InputData != String.Empty)
            //{
            //    //             textBoxIn.Text = InputData;
            //    // because of different threads this
            //    // does not work properly !!
            //    SetText(InputData);
            //}
        }
        private void SetText(string text)
        {
            // InvokeRequired required compares the thread ID of the
            // calling thread to the thread ID of the creating thread.
            // If these threads are different, it returns true.
            //if (this.textBoxIn.InvokeRequired)
            //{
            //    SetTextCallback d = new SetTextCallback(SetText);
            //    this.Invoke(d, new object[] { text });
            //}
            //else this.textBoxIn.Text += text;
        }

        private void buttonWrite_Click(object sender, EventArgs e)
        {
            bool error = false;
            foreach (Control c in groupBox2.Controls)
            {
                if (errorProvider1.GetError(c) != "")
                {
                    string temp = "";
                    error = true;
                    temp = errorProvider1.GetError(c);
                    //MessageBox.Show(temp);
                    errorProvider1.SetError(c, "");
                    errorProvider1.SetError(c, temp);
                    c.Focus();
                    break;
                }

            }
            if (!error)
            {
                CultureInfo ci = new CultureInfo("en-US");
                bank.Pgain = Double.Parse(textBoxPgain.Text, NumberStyles.Float, ci);
                bank.Igain = Double.Parse(textBoxIgain.Text, NumberStyles.Float, ci);
                bank.Dgain = Double.Parse(textBoxDgain.Text, NumberStyles.Float, ci);
                bank.FF1 = Double.Parse(textBoxFF1.Text, NumberStyles.Float, ci);
                bank.maxI = Double.Parse(textBoxMaxI.Text, NumberStyles.Float, ci);
                bank.maxOutput = Double.Parse(textBoxMaxOutput.Text, NumberStyles.Float, ci);
                bank.bias = Double.Parse(textBoxBias.Text, NumberStyles.Float, ci);
                bank.deadBand = Double.Parse(textBoxDeadBand.Text, NumberStyles.Float, ci);
                bank.CmdMultiplier = Double.Parse(textBoxCmdMultiplier.Text, NumberStyles.Float, ci);
                bank.maxErrorShutOff = Double.Parse(textBoxMaxError.Text, NumberStyles.Float, ci);
                bank.Address = Double.Parse(textBoxAddress.Text, NumberStyles.Float, ci);

                bank.IsCmdDirStep = radioButtonDirStep.Checked;
                bank.CalcInterval = (double)comboBoxCalcInterval.SelectedIndex;

                textBoxControlSum.Text =  bank.CalculateCSum().ToString();

                comport.DiscardInBuffer();
                Thread.Sleep(100);
                comport.DiscardInBuffer();
                if (Connect())
                {
                    List<byte> bytes = new List<byte>(0);
                    lblBank.Text = "";
                    for (int i = 0; i < 16; i++)
                    {
                        bytes.Add((byte)'W');       //Command 'WRITE TO RAM'
                        bytes.Add((byte)i);         //Address
                        bytes.Add(bank.Bank[i]);    //Value
                        comport.Write(bytes.ToArray(), 0, bytes.Count);
                        bytes.Clear();
                        lblBank.Text = lblBank.Text+Convert.ToString(bank.Bank[i], 16) + " ";
                    }
                    if (comboBank.SelectedIndex > 0)
                    {
                        bytes.Add((byte)'S');                            //Command 'SAVE RAM TO EEPROM'
                        bytes.Add((byte)(comboBank.SelectedIndex - 1));  //EEPROM bank address
                        comport.Write(bytes.ToArray(), 0, bytes.Count);
                        bytes.Clear();
                    }
                }
                
                
            }
            //if(errorProvider1.GetError(textBoxPgain)=="")
             //   dataBank.Pgain = Double.Parse(textBoxPgain.Text, NumberStyles.Float,
               //     new CultureInfo("en-US"));
            //List<byte> bytes = new List<byte>(0);

            //bytes.Add((byte)Convert.ToChar((string)comboBank.SelectedItem));
            //if(textBoxPgain.Text != "")
            //    bytes.Add(Convert.ToByte(textBoxPgain.Text));
            //if(textBoxIgain.Text != "")
            //    bytes.Add(Convert.ToByte(textBoxIgain.Text));
            //comport.Write(bytes.ToArray(), 0, bytes.Count);

        }

        private bool Connect()
        {
            if (comport != null)
            {
                if (comport.IsOpen)
                {
                    List<byte> bytes = new List<byte>(0);
                    bytes.Add((byte)'V');
                    bytes.Add((byte)comboBoxSelectServo.SelectedIndex);
                    bytes.Add((byte)'Z');
                    comport.Write(bytes.ToArray(), 0, 3);
                    return true;
                }
                else return false;
            }
            else return false;
        }
        

        private void buttonRead_Click(object sender, EventArgs e)
        {
            Thread.Sleep(100);
            comport.DiscardInBuffer();
            InputData.Clear();
            if (Connect())
            {
                List<byte> bytes = new List<byte>(0);
                bytes.Add((byte)'Z');                            //Command 'End analyze mode'
                bytes.Clear();
                comport.Write(bytes.ToArray(), 0, bytes.Count);
                Thread.Sleep(200);
                InputData.Clear();
                if (comboBank.SelectedIndex > 0)
                {
                    bytes.Add((byte)'L');                            //Command 'LOAD EEPROM TO RAM'
                    bytes.Add((byte)(comboBank.SelectedIndex - 1));  //EEPROM bank address
                    comport.Write(bytes.ToArray(), 0, bytes.Count);
                    bytes.Clear();
                    Thread.Sleep(50);
                }
                for (int i = 0; i < 16; i++)
                {
                    bytes.Add((byte)'R');       //Command 'READ FROM RAM'
                    bytes.Add((byte)i);         //Address
                    comport.Write(bytes.ToArray(), 0, bytes.Count);
                    Thread.Sleep(20);
                    bytes.Clear();
                }
                Thread.Sleep(500);
                if (InputData.Count == 16)
                {
                    bank.Bank = InputData.ToArray();
                    CultureInfo ci = new CultureInfo("en-US");
                    textBoxPgain.Text = Convert.ToString(bank.Pgain, ci);
                    textBoxIgain.Text = Convert.ToString(bank.Igain, ci);
                    textBoxDgain.Text = Convert.ToString(bank.Dgain, ci);
                    textBoxFF1.Text = Convert.ToString(bank.FF1, ci);
                    textBoxMaxI.Text = Convert.ToString(bank.maxI, ci);
                    textBoxMaxOutput.Text = Convert.ToString(bank.maxOutput, ci);
                    textBoxBias.Text = Convert.ToString(bank.bias, ci);
                    textBoxDeadBand.Text = Convert.ToString(bank.deadBand, ci);
                    textBoxCmdMultiplier.Text = Convert.ToString(bank.CmdMultiplier, ci);
                    textBoxMaxError.Text = Convert.ToString(bank.maxErrorShutOff, ci);
                    textBoxAddress.Text = Convert.ToString(bank.Address, ci);

                    radioButtonDirStep.Checked = bank.IsCmdDirStep ;

                    comboBoxCalcInterval.SelectedIndex = (int)bank.CalcInterval;

                    if (bank.Bank[15] == bank.CalculateCSum())
                        textBoxControlSum.Text = "OK";
                    else
                        textBoxControlSum.Text = "Failed";

                }
                else
                    MessageBox.Show("Error while reading data");
                
            }
            //perfChart1.DrawValues.Add(50);
            //perfChart1.Refresh();
            //MessageBox.Show(comport.WriteBufferSize.ToString());
        }

        private void textBoxValidating(object sender, EventArgs e)
        {
            Regex regex = new Regex(regexStrings[((TextBox)sender).Name]);
            if (regex.IsMatch(((TextBox)sender).Text))
            {
                double value = Double.Parse(((TextBox)sender).Text, NumberStyles.Float,new CultureInfo("en-US"));
                //double value = Convert.ToDouble(((TextBox)sender).Text);
                double[] limit = Limits[((TextBox)sender).Name];
                if (value < limit[0] || value > limit[1])
                    errorProvider1.SetError((TextBox)sender,
                    "The number reach minimum/maximum limits\n\rplease enter a number between :\n\r"+
                    (limit[0]).ToString() + " and " + (limit[1]).ToString());
                else
                    errorProvider1.SetError((TextBox)sender, String.Empty);
            }
            else
            {
                errorProvider1.SetError((TextBox)sender,
                    "Only numbers may be entered here");
            }

        }

        private void comboBoxSelectServo_SelectedValueChanged(object sender, EventArgs e)
        {

        }

        private void textBox_Leave(object sender, EventArgs e)
        {
            Regex regex = new Regex(regexStrings[((TextBox)sender).Name]);
            if (regex.IsMatch(((TextBox)sender).Text))
            {
                double value = Double.Parse(((TextBox)sender).Text, NumberStyles.Float, new CultureInfo("en-US"));
                
                //double value = Convert.ToDouble(((TextBox)sender).Text);
                double[] limit = Limits[((TextBox)sender).Name];
                if (value < limit[0])
                    value = limit[0];
                else if( value > limit[1])
                    value = limit[1];
                double val2 = value*Math.Pow(2.0 , bitsAfterDot[((TextBox)sender).Name]);
                int valint = Convert.ToInt32( Math.Floor(val2));
                value = Convert.ToDouble(valint) / Math.Pow(2.0, bitsAfterDot[((TextBox)sender).Name]);
                ((TextBox)sender).Text = Convert.ToString(value, new CultureInfo("en-US"));
                
            }
            else
            {
                errorProvider1.SetError((TextBox)sender,
                    "Only numbers may be entered here");
            }
        }

        private void perfChart1_MouseMove(object sender, MouseEventArgs e)
        {
            if(toolTip1.GetToolTip(perfChart1)!=e.X.ToString() + "," + e.Y.ToString())
                toolTip1.SetToolTip(perfChart1, e.X.ToString() + "," + e.Y.ToString());
        }

        private void perfChart1_MouseLeave(object sender, EventArgs e)
        {
            toolTip1.SetToolTip(perfChart1, "");
        }

        private void timer1_Tick(object sender, EventArgs e)
        {

        }

        private void buttonAnalyze_Click(object sender, EventArgs e)
        {
            Thread.Sleep(100);
            comport.DiscardInBuffer();
            InputData.Clear();
            if (Connect())
            {
                List<byte> bytes = new List<byte>(0);
                bytes.Add((byte)'A');                            //Command 'Start analyze mode'
                //bytes.Add((byte)'T');                          //Command 'Time scale' TO DO not yet implemented
                bytes.Add((byte)'G');                            //Command 'Goto'
                Int16 gt = Int16.Parse(textBoxGoTo.Text);
                bytes.Add((byte)(gt & 0xFF));                    //Goto low byte
                bytes.Add((byte)(gt >> 8));                      //Goto high byte
                comport.Write(bytes.ToArray(), 0, bytes.Count);
                bytes.Clear();
                int n = 0;//(InputData.Count < 800)
                while(  (n<10))
                {
                Thread.Sleep(100);
                    n++;
                }
                bytes.Add((byte)'Z');                            //Command 'End analyze mode'
                comport.Write(bytes.ToArray(), 0, bytes.Count);
                perfChart1.DrawValues.Clear();
                int si = 0;
                for (int i = 0; i < 780; i++)
                {
                    if (i < InputData.Count)
                    {
                        si = Convert.ToInt32((sbyte)InputData[i]);
                        perfChart1.DrawValues.Add(Convert.ToDecimal(si + 50));
                    }
                    else
                        perfChart1.DrawValues.Add(50);
                }
                perfChart1.Refresh();

            }
        }

        private void buttonGoto_Click(object sender, EventArgs e)
        {
            if (Connect())
            {
                List<byte> bytes = new List<byte>(0);
                bytes.Add((byte)'Z');                            //Command 'End analyze mode'
                //bytes.Add((byte)'T');                          //Command 'Time scale' TO DO not yet implemented
                bytes.Add((byte)'G');                            //Command 'Goto'
                Int16 gt = Int16.Parse(textBoxGoTo.Text);
                bytes.Add((byte)(gt & 0xFF));                    //Goto low byte
                bytes.Add((byte)(gt >> 8));                      //Goto high byte
                comport.Write(bytes.ToArray(), 0, bytes.Count);
                bytes.Clear();
            }
        }

    }
}
/*
X	;eXecute Continious Goto
V	;Select controller with address 
C	;Continious Goto ON
c	;Continious Goto OFF
G	;Goto
S	;Saving parameters to EEPROM
L	;Loading parameters from EEPROM
A	;Start analyze mode
Z	;End analyze mode
+	;Reset
U	;UART speed
R	;Read byteNo from RAMbank
W	;Write byteNo to RAMbank
*/